package com.sia.springcloud.protocol;

import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.code.DataType;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.ip.IpParameters;
import com.serotonin.modbus4j.locator.BaseLocator;
import com.serotonin.modbus4j.msg.WriteCoilRequest;
import com.serotonin.modbus4j.msg.WriteCoilResponse;
import com.sia.springcloud.model.Device;
import com.sia.springcloud.model.Point;
import com.sia.springcloud.protocol.model.ModbusPoint;
import com.sia.springcloud.protocol.model.ModbusDevice;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * @Author: Sirius
 * @Date: 2021/10/3 20:05
 * @Description: Modbus数采方法
 **/
@Slf4j
@Data
@Component
public class Modbus implements IProtocol {

    private Long id = 1884608L;

    private static ModbusFactory modbusFactory = new ModbusFactory();


    //里面存放的是deviceId和对应的ModbusMaster
    //static保证ModbusCollectJob可以不传入dataMap也能获取并且修改，volatile保证如果修改了会对其他线程产生影响
    private static volatile Map<Integer, ModbusMaster> masterMap = new HashMap<>(64);
    private static volatile int collectSum = 0;


    /**
     * 获取ModbusMaster
     * <p>
     * 首先判断HashMap中对应deviceId是否有属于自己的ModbusMaster，如果没有就获取信息create一个TcpMaster，放入HashMap中
     *
     * @param modbusDevice
     * @return
     * @throws ModbusInitException
     */
    public ModbusMaster getMaster(ModbusDevice modbusDevice) throws ModbusInitException {
        Integer deviceId = modbusDevice.getId();
        //IP
        String host = modbusDevice.getHost();
        //端口
        Integer port = modbusDevice.getPort();
        //超时时间
        Integer timeout = modbusDevice.getTimeout();
        //重连次数
        Integer connectionLimit = modbusDevice.getConnectionLimit();

        ModbusMaster modbusMaster = masterMap.get(deviceId);

        //首先判断这个map中是否有该设备和该设备对应的ModbusMaster，如果没有就新建一个放进去
        if (null == modbusMaster) {
            IpParameters params = new IpParameters();
            params.setHost(host);
            params.setPort(port);

            modbusMaster = modbusFactory.createTcpMaster(params, true);
            //设置超时时间
            modbusMaster.setTimeout(timeout);
            //设置重连次数
            modbusMaster.setRetries(connectionLimit);
            modbusMaster.init();

            masterMap.put(deviceId, modbusMaster);
        }
        return modbusMaster;
    }

    /**
     * 获取 Value
     * <p>
     * 这里的type是存储在数据库中的，也应该通过pointInfo传递过来
     *
     * @param modbusMaster ModbusMaster
     * @return String Value
     * @throws ModbusTransportException ModbusTransportException
     * @throws ErrorResponseException   ErrorResponseException
     */
    public String readValue(ModbusMaster modbusMaster, ModbusPoint modbusPoint) throws ModbusTransportException, ErrorResponseException {
        log.info("----------------{}---------------", collectSum++);


        int slaveId = modbusPoint.getSlaveId();
        int functionCode = modbusPoint.getFunctionCode();
        int offset = modbusPoint.getOffset();


        //type：原本是需要通过类型转换方法，将类型转换成对应的int类型代码，但是由于我数据库中直接存储的就是int，并不是存储的类型字符串
        //所以我这里并不需要进行转换
        String typeStr = modbusPoint.getTypeStr();
        int type = getValueType(typeStr);


        //根据功能码，选择不同的处理方式，最后统一返回String类型的数值
        switch (functionCode) {
            case 1:
                BaseLocator<Boolean> coilLocator = BaseLocator.coilStatus(slaveId, offset);
                Boolean coilValue = modbusMaster.getValue(coilLocator);
                return String.valueOf(coilValue);
            case 2:
                BaseLocator<Boolean> inputLocator = BaseLocator.inputStatus(slaveId, offset);
                Boolean inputStatusValue = modbusMaster.getValue(inputLocator);
                return String.valueOf(inputStatusValue);
            case 3:
                //log.warn("没有设定好type类型");
                BaseLocator<Number> holdingLocator = BaseLocator.holdingRegister(slaveId, offset, type);
                Number holdingValue = modbusMaster.getValue(holdingLocator);
                log.info("读取的数据为 {}", holdingLocator);
                return String.valueOf(holdingValue);
            case 4:
                //log.warn("没有设定好type类型");
                BaseLocator<Number> inputRegister = BaseLocator.inputRegister(slaveId, offset, type);
                Number inputRegisterValue = modbusMaster.getValue(inputRegister);
                return String.valueOf(inputRegisterValue);
            default:
                return "0";
        }
    }

    /**
     * 写入value
     *
     * @param modbusMaster
     * @param modbusPoint
     * @return
     * @throws ModbusTransportException
     * @throws ErrorResponseException
     */
    public boolean writeValue(ModbusMaster modbusMaster, ModbusPoint modbusPoint) throws ModbusTransportException, ErrorResponseException {

        int slaveId = modbusPoint.getSlaveId();
        int functionCode = modbusPoint.getFunctionCode();
        int offset = modbusPoint.getOffset();

        //type：原本是需要通过类型转换方法，将类型转换成对应的int类型代码，但是由于我数据库中直接存储的就是int，并不是存储的类型字符串
        //所以我这里并不需要进行转换
        String typeStr = modbusPoint.getTypeStr();
        int type = getValueType(typeStr);


        switch (functionCode) {
            case 1:
                log.error("这里是一个未完成的bug，需要对value进行类型转换");
                //boolean coilValue = value;
                boolean coilValue = false;
                WriteCoilRequest coilRequest = new WriteCoilRequest(slaveId, offset, coilValue);
                WriteCoilResponse coilResponse = (WriteCoilResponse) modbusMaster.send(coilRequest);
                return !coilResponse.isException();
            case 3:
                //BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, offset, getValueType(type));
                BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, offset, type);
                //modbusMaster.setValue(locator, value(type, value));
                log.error("这里是一个未完成的bug，需要对value进行类型转换");
                modbusMaster.setValue(locator, false);
                return true;
            default:
                return false;
        }
    }

    //public String read(Device device, Point point) throws ErrorResponseException, ModbusTransportException, ModbusInitException {
    //    ModbusDevice modbusDevice = ModbusDevice.reconvert(device);
    //    ModbusPoint modbusPoint = ModbusPoint.reconvert(point);
    //
    //    ModbusMaster modbusMaster = getMaster(modbusDevice);
    //
    //    return readValue(modbusMaster,modbusPoint);
    //}


    // 21KB
    private String str1 = "首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。\n";

    // 12KB
    private String str2 = "首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做";

    // 3KB
    private String str3 = "首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连续几次Error才会触发报警，而我们定时任务的周期性的特性是不容易触发连续的Error。首先是单机问题，如何划分一个业务不是很重要，这一块本来就比较复杂，有可能每个人都说自己的业务都重要，其次是如果单机挂了 这个挂有可能是宕机，有可能是其他的一些情况，这个时间如何能保证我们再可接受的范围之间恢复，这些都是难点。目前我们使用定时任务的时候，如果想让它马上执行一次，这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job。还有个是我们需要更改定时任务执行时间，比如现在有个需求是从每12个小时执行一次变成每6小时执行一次，我们又得修改代码，提交pr，然后打包上线，只是修改一个时间又得花费我们很多时间。无法暂停我们的定时任务，当我们的定时任务可能出现一些问题，比如一些定时报警的需求，当报警突然变得很多，这个时候需要暂停一下让其停止发送报警，这个时候可能我们可以用一些分布式配置的开关去做，再逻辑中判断定时任务开关是否打开，然后来做。这样做虽然也比较简单，但是我们这样需要新添加一些与任务无关的逻辑。缺少对定时任务的监控，任务失败之后开发人员无从得知，有人说不是有Error日志吗，如果一个Error日志就一次报警那你们的服务能受得了吗，一般来说连";

    private static volatile int send1 = 0;

    public String read(Device device, Point point) throws ErrorResponseException, ModbusTransportException, ModbusInitException {
        ModbusDevice modbusDevice = ModbusDevice.reconvert(device);
        ModbusPoint modbusPoint = ModbusPoint.reconvert(point);

        ModbusMaster modbusMaster = getMaster(modbusDevice);
        Modbus.send1++;

        if (send1 % 500 == 0) {

            System.out.println("test发送第：" + send1 + " 条数据" + "，每条数据的长度为：" + str3.length() / 1024.0 * 3);
            return String.valueOf(System.currentTimeMillis());
        }
        return "1234";
    }


    public Boolean write(Device device, Point point) throws Exception {
        ModbusDevice modbusDevice = ModbusDevice.reconvert(device);
        ModbusPoint modbusPoint = ModbusPoint.reconvert(point);


        ModbusMaster modbusMaster = getMaster(modbusDevice);
        return writeValue(modbusMaster, modbusPoint);
    }


    public void schedule() {

        /*
        TODO:设备状态
        上传设备状态，可自行灵活拓展，不一定非要在schedule()接口中实现，也可以在read中实现设备状态的设置；
        你可以通过某种判断机制确定设备的状态，然后通过driverService.deviceEventSender接口将设备状态交给SDK管理。

        设备状态（DeviceStatus）如下：
        ONLINE:在线
        OFFLINE:离线
        MAINTAIN:维护
        FAULT:故障
         */
        //driverContext.getDriverMetadata().getDeviceMap().keySet().forEach(id -> driverService.deviceEventSender(id, Common.Device.Event.HEARTBEAT, Common.Device.Status.ONLINE));

    }



    //不同类型的字符段，需要的是不同类型的
    public int getValueType(String typeStr) {
        int type;
        switch (typeStr) {
            case "bit":
                type = 0;
                break;
            case "char":
                type = 1;
                break;
            case "short":
                type = 2;
                break;
            case "int":
                type = 3;
                break;
            case "real":
                type = 4;
                break;
            case "smallshort":
                type = 8;
                break;
            case "smallint":
                type = 9;
                break;
            case "smallreal":
                type = 10;
                break;
            default:
                type = 3;
        }
        return type;

    }


}
